package cn.cloudtogo.support.mysql.table;

import cn.cloudtogo.common.Assert;
import cn.cloudtogo.support.mysql.column.ColumnDefinition;
import cn.cloudtogo.support.mysql.column.Types;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

import static cn.cloudtogo.common.Assert.*;

/**
 * @author yaolianhua789@gmail.com
 **/
public final class TableBuilder {

    private TableBuilder() {
    }

    private static String buildColumn(ColumnDefinition column) {
        StringBuilder columnBuilder = new StringBuilder();

        argument(StringUtils.hasText(column.getName()), () -> "column name is null");
        notNull(column.getTypes(), () -> "Types is null");
        notNull(column.getTypes().getColumnType(), () -> "column type is null");

        Types.ColumnType type = column.getTypes().getColumnType();
        String datatype;
        if (Types.ColumnType.VARCHAR.equals(type)) {
            datatype = String.format("VARCHAR(%s)", StringUtils.hasText(column.getTypes().getLength()) ? column.getTypes().getLength() : 500);
        } else {
            datatype = column.getTypes().getColumnType().name();
        }

        columnBuilder.append(String.format("`%s` %s ", column.getName(), datatype));
        if (column.isNotNull()) {
            columnBuilder.append("not null ");
        } else {
            columnBuilder.append("null ");
        }

        String defaultValue = column.getDefaultValue();
        if (StringUtils.hasText(defaultValue)) {
            //price DOUBLE default 0.0
            columnBuilder.append(String.format("default %s ", defaultValue));
        }

        if (column.isAutoIncrement()) {
            state(Types.ColumnType.INT.equals(column.getTypes().getColumnType()), () -> String.format("can not auto increment for '%s'", column.getTypes().getColumnType().name()));
            columnBuilder.append("auto_increment ");
        }

        columnBuilder.append(String.format("comment '%s'", column.getComment()));

        return columnBuilder.toString();

    }

    public static String buildSql(TableTemplate table, String schema) {
        notNull(table, () -> "table template is null");
        argument(StringUtils.hasText(schema), () -> "schema is null");
        argument(StringUtils.hasText(table.getName()), () -> "table name is null");
        state(!table.getColumns().isEmpty(), () -> "table columns is empty");

        List<ColumnDefinition> primaryDefinitions = table.getColumns()
                .stream()
                .filter(ColumnDefinition::isPrimaryKey)
                .collect(Collectors.toList());
        Assert.state(primaryDefinitions.size() > 0, () -> String.format("No primary key for table '%s'", table.getName()), 400);

        for (ColumnDefinition primary : primaryDefinitions) {
            Assert.state(primary.isNotNull(), () -> "Primary key can not be null", 400);
        }

        List<String> primariesNoAutoIncrement = primaryDefinitions
                .stream()
                .filter(e -> !e.isAutoIncrement())
                .map(ColumnDefinition::getName)
                .collect(Collectors.toList());

        List<String> autoIncrements = primaryDefinitions.stream()
                .filter(ColumnDefinition::isAutoIncrement)
                .map(ColumnDefinition::getName)
                .collect(Collectors.toList());
        Assert.state(autoIncrements.size() <= 1, () -> "There can only be at most one auto-incrementing column", 400);

        String primaryKeys = primariesNoAutoIncrement
                .stream()
                .map(e -> String.format("`%s`", e))
                .collect(Collectors.joining(","));
        if (!autoIncrements.isEmpty()) {
            String autoIncrement = autoIncrements.get(0);
            if (StringUtils.hasText(primaryKeys)) {
                primaryKeys = String.format("`%s`", autoIncrement).concat(",") + primaryKeys;
            } else {
                primaryKeys = String.format("`%s`", autoIncrement);
            }
        }

        StringBuilder sqlBuilder = new StringBuilder();

        sqlBuilder.append(String.format("create table if not exists %s.%s\n", schema, table.getName()));
        sqlBuilder.append("(\n");

        table.getColumns().stream().map(TableBuilder::buildColumn).forEach(columnSql -> sqlBuilder.append(String.format("\t%s,\n", columnSql)));

        //constraint order_detail_order_id_IDX unique (order_id)
        List<String> uniqueColumns = table.getColumns().stream()
                .filter(ColumnDefinition::isUniqueIndex)
                .filter(ColumnDefinition::isNotNull)
                .map(ColumnDefinition::getName)
                .collect(Collectors.toList());
        uniqueColumns.forEach(uniqueColumn -> sqlBuilder.append(String.format("\tconstraint %s_%s_uindex unique (%s),\n", table.getName(), uniqueColumn, uniqueColumn)));
        sqlBuilder.append(String.format("\tconstraint %s_pk primary key (%s)\n", table.getName(), primaryKeys));

        sqlBuilder.append(")\n");
        sqlBuilder.append(String.format("comment '%s';\n", table.getComment()));

        return sqlBuilder.toString();
    }


}
